package edu.uwm.cs552;

import java.awt.Graphics2D;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Observable;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * The rails of a player.
 * There are three kinds of rails:
 * <ol>
 * <li> Completed track.
 * <li> Track current under construction.
 * <li> Track being considered for construction
 *      (visible only to the player proposing it).
 * </ol>
 */
public class TrackStatus extends Observable {

	private Set<HexEdge> built = new HashSet<HexEdge>();
	private Map<HexEdge,RailState> underConstruction = new HashMap<HexEdge,RailState>();
	//private Queue<HexEdge> proposed = new LinkedBlockingQueue<HexEdge>();
	private LinkedList<HexEdge> proposed = new LinkedList<HexEdge>();
	
	/**
	 * Draw the track on a graphics context.
	 * @param g graphics context, cannot be null
	 * @param scale width of hexagons
	 * @param showProposed whether to show proposed rails (only for the player
	 * proposing the track).
	 */
	public void draw(Graphics2D g, double scale, boolean showProposed) {
		for (HexEdge e : built) {
			RailState.BUILT.draw(g, e, scale);
		}
		for (Map.Entry<HexEdge, RailState> e : underConstruction.entrySet()) {
			e.getValue().draw(g, e.getKey(), scale);
		}
		if (showProposed) {
			for (HexEdge e : proposed) {
				RailState.PROPOSED.draw(g, e, scale);
			}
		}
	}
	
	/**
	 * Return state of rail on this edge.
	 * Either built or under construction.
	 * (This does not take into account proposed rail construction.)
	 * @param e edge in question, must not be null
	 * @return rail state or null if no rail at this point.
	 */
	public RailState getTrack(HexEdge e) {
		if (built.contains(e)) return RailState.BUILT;
		return underConstruction.get(e);
	}
	
	/**
	 * Move construction forward for track being constructed. 
	 * @param turns amount of turns to go forward with construction
	 */
	public void progress(int turns) {
		if (underConstruction.isEmpty()) return;
		Map<HexEdge,RailState> newUnder = new HashMap<HexEdge,RailState>();
		for (Map.Entry<HexEdge, RailState> e : underConstruction.entrySet()) {
			RailState rs = e.getValue().progress(turns);
			setChanged();
			if (rs == RailState.BUILT) {
				built.add(e.getKey());
			} else {
				newUnder.put(e.getKey(), rs);
			}
		}
		underConstruction.clear();
		underConstruction.putAll(newUnder);
		notifyObservers(newUnder);
	}
	
	/**
	 * Start to construct a piece of track.
	 * @param e edge on which to construct track.
	 */
	public void constructTrack(HexEdge e) {
		underConstruction.put(e, RailState.startBuildState());
		setChanged();
		notifyObservers(e);
	}
	
	/**
	 * Remove and return the next piece of track proposed for construction.
	 * @return proposed track or null if nothing proposed.
	 */
	public HexEdge nextProposed() {
		return proposed.poll();
	}
	
	public void pushProposed(HexEdge h) {
		proposed.addFirst(h);
		setChanged();
		notifyObservers(h);
	}
	
	/**
	 * This player proposed a new section of track.
	 * @param e edge on which track is proposed to be laid.
	 */
	public void propose(HexEdge e) {
		if (proposed.contains(e)) return;
		proposed.add(e);
		setChanged();
		notifyObservers(e);
	}
	
	/**
	 * Clear all proposals currently pending.
	 */
	public void clearProposed() {
		proposed.clear();
		setChanged();
		notifyObservers(this);
	}

	public void removeProposal(HexEdge e) {
		if (proposed.remove(e)) setChanged();
		notifyObservers(e);
	}
}
